package cn.threewaters.qtyy.web.controller;

import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import cn.threewaters.qtyy.common.bean.ResponseJson;
import cn.threewaters.qtyy.config.shiro.ShiroManager;
import cn.threewaters.qtyy.dit.one.entity.SysFunction;
import cn.threewaters.qtyy.dit.one.entity.SysUser;
import cn.threewaters.qtyy.dit.one.entity.base.OneBaseModel;
import cn.threewaters.qtyy.service.sys.SysFunctionService;
import cn.threewaters.qtyy.util.hutool.core.util.StrUtil;
import cn.threewaters.qtyy.web.facade.MenuTree;
import cn.threewaters.qtyy.web.facade.TreeNode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import springfox.documentation.annotations.ApiIgnore;

@Api(tags = "登录控制器")
@Controller
@Slf4j
public class HomeController {

	@Resource
	private SysFunctionService functionService;

	@Resource
	@Qualifier("oneJdbcTemplate")
	private JdbcTemplate oneJdbcTemplate;

	@ApiIgnore
	@ApiOperation(value = "根目录")
	@RequestMapping("/")
	public String root() {
		return "redirect:/index";
	}

	@ApiIgnore
	@ApiOperation(value = "首页")
	@RequestMapping("/index")
	public String index(ModelMap modelMap) throws Exception {
		List<SysFunction> sysFunctions = functionService.selectList(new EntityWrapper<SysFunction>().ne("parent_id", -1)
				.eq("fun_type", "1").eq("active_flag", OneBaseModel.ACTIVE_FLAG_YES).orderBy("sort_no"));
		MenuTree menuTree = new MenuTree();
		List<Object> menuLists = menuTree.menuList(sysFunctions);
		modelMap.put("menus", menuLists);

		List<Map<String, Object>> infoList = oneJdbcTemplate
				.queryForList("select * from la_weather order by checktime desc limit 1");
		modelMap.put("weather", infoList.get(0));
		return "index";
	}

	@ApiIgnore
	@ApiOperation(value = "登录页面")
	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public String login(String message, ModelMap modelMap) {
		if (StrUtil.isNotEmpty(message)) {
			modelMap.addAttribute("message", message);
		}
		return "login";
	}

	@ApiIgnore
	@ApiOperation(value = "登录动作")
	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public String login(HttpServletRequest req, SysUser user, RedirectAttributes attr) {
		if (StrUtil.isEmpty(user.getUsername()) || StrUtil.isEmpty(user.getUsername())) {
			attr.addAttribute("message", "用户名或密码不能为空");
			return "redirect:/login";
		}
		String userName = user.getUsername();
		String password = user.getPassword();
		// 开始调用shiro验证
		UsernamePasswordToken token = new UsernamePasswordToken(userName, password, "login");
		// 获取当前的subject
		Subject currentUser = ShiroManager.getSubject();
		try {
			// 在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查
			// 每个Realm都能在必要时对提交的AuthenticationTokens作出反应
			// 所以这一步在调用login(token)方法时,它会走到doGetAuthenticationInfo()方法中,具体验证方式详见此方法
			log.debug("对用户[" + userName + "]进行登录验证..验证开始");
			currentUser.login(token);
			log.debug("对用户[" + userName + "]进行登录验证..验证通过");
			ShiroManager.getSession().setAttribute("userInfo", ShiroManager.getUserInfo());
			ShiroManager.getSession().setAttribute("loginName", ShiroManager.getUsername());
		} catch (UnknownAccountException uae) {
			log.debug("对用户[" + userName + "]进行登录验证..验证未通过,未知账户");
			attr.addAttribute("message", uae.getMessage());
		} catch (IncorrectCredentialsException ice) {
			log.debug("对用户[" + userName + "]进行登录验证..验证未通过,错误的凭证");
			attr.addAttribute("message", "密码不正确");
		} catch (LockedAccountException lae) {
			log.debug("对用户[" + userName + "]进行登录验证..验证未通过,账户已锁定");
			attr.addAttribute("message", "账户已锁定");
		} catch (ExcessiveAttemptsException eae) {
			log.debug("对用户[" + userName + "]进行登录验证..验证未通过,错误次数过多");
			attr.addAttribute("message", "用户名或密码错误次数过多");
		} catch (AuthenticationException ae) {
			// 通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景
			log.debug("对用户[" + userName + "]进行登录验证..验证未通过,堆栈轨迹如下");
			ae.printStackTrace();
			attr.addAttribute("message", "用户名或密码不正确");
		}
		if (req.getParameter("forceLogout") != null) {
			attr.addAttribute("error", "您已经被管理员强制退出，请重新登录");
			return "redirect:/login";
		}
		// 验证是否登录成功
		if (currentUser.isAuthenticated()) {
			return "redirect:/index";
		} else {
			token.clear();
			return "redirect:/login";
		}
	}

	@ApiOperation(value = "API登录认证")
	@ApiImplicitParams({
			@ApiImplicitParam(paramType = "query", dataType = "string", name = "loginName", value = "用户名", required = true),
			@ApiImplicitParam(paramType = "query", dataType = "string", name = "loginPwd", value = "密码", required = true) })
	@RequestMapping(value = "/apilogin", method = RequestMethod.POST)
	@ResponseBody
	public ResponseJson login(@ApiIgnore SysUser user) throws Exception {

		String message = "登录成功";

		String userName = user.getUsername();
		String password = user.getPassword();

		// 开始调用shiro验证
		UsernamePasswordToken token = new UsernamePasswordToken(userName, password, "login");
		// 获取当前的subject
		Subject currentUser = ShiroManager.getSubject();
		try {
			// 在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查
			// 每个Realm都能在必要时对提交的AuthenticationTokens作出反应
			// 所以这一步在调用login(token)方法时,它会走到doGetAuthenticationInfo()方法中,具体验证方式详见此方法
			log.debug("对用户[" + userName + "]进行登录验证..验证开始");
			currentUser.login(token);
			log.debug("对用户[" + userName + "]进行登录验证..验证通过");
			ShiroManager.getSession().setAttribute("userInfo", ShiroManager.getUserInfo());
			ShiroManager.getSession().setAttribute("loginName", ShiroManager.getUsername());
		} catch (UnknownAccountException uae) {
			log.debug("对用户[" + userName + "]进行登录验证..验证未通过,未知账户");
			message = uae.getMessage();
		} catch (IncorrectCredentialsException ice) {
			ice.printStackTrace();
			log.debug("对用户[" + userName + "]进行登录验证..验证未通过,错误的凭证");
			message = "密码不正确";
		} catch (LockedAccountException lae) {
			log.debug("对用户[" + userName + "]进行登录验证..验证未通过,账户已锁定");
			message = "账户已锁定";
		} catch (ExcessiveAttemptsException eae) {
			log.debug("对用户[" + userName + "]进行登录验证..验证未通过,错误次数过多");
			message = "用户名或密码错误次数过多";
		} catch (AuthenticationException ae) {
			// 通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景
			log.debug("对用户[" + userName + "]进行登录验证..验证未通过,堆栈轨迹如下");
			ae.printStackTrace();
			message = "用户名或密码不正确";
		}
		// 验证是否登录成功
		if (currentUser.isAuthenticated()) {
			return ResponseJson.builder().success(true).msg(message).build();
		} else {
			token.clear();
			return ResponseJson.builder().success(false).msg(message).build();
		}

	}

	@ApiOperation(value = "仓房信息树形列表查询")
	@RequestMapping(value = "/index/list", method = RequestMethod.GET)
	@ResponseBody
	public ResponseJson indexTreeJsonData() throws Exception {
		Map<String, TreeNode> resultMap = Maps.newLinkedHashMap();
		List<TreeNode> resultList = Lists.newArrayList();
		List<Map<String, Object>> queryForList = oneJdbcTemplate.queryForList(
				"SELECT a.`code` orgcode, a.`name` orgname, b.`code` companycode, b.`name` companyname FROM `la_storage` a, `la_company` b  WHERE a.`company_code` = b.`code`  ORDER BY  b.`code`,a.`code`");
		for (Map<String, Object> map : queryForList) {
			String companycode = map.get("companycode").toString();
			String companyname = map.get("companyname").toString();
			String orgcode = map.get("orgcode").toString();
			String orgname = map.get("orgname").toString();
			if (resultMap.get(companycode) == null) {
				TreeNode treeNode = new TreeNode();
				treeNode.setId(companycode);
				treeNode.setName(companyname);
				List<TreeNode> children = treeNode.getChildren();
				children.add(new TreeNode(orgcode, orgname));
				resultMap.put(companycode, treeNode);
				resultList.add(treeNode);
			} else {
				List<TreeNode> children = resultMap.get(companycode).getChildren();
				children.add(new TreeNode(orgcode, orgname));
			}
		}
		return ResponseJson.builder().success(true).msg("查询成功").obj(resultList).build();
	}

}
